//! # 模板引擎
//!
//! 用于渲染项目模板和代码生成

use crate::commands::init::ProjectConfig;
use crate::config::CliConfig;
use crate::error::{CliError, CliResult};
use handlebars::Handlebars;
use serde_json::json;
use std::collections::HashMap;
use std::path::Path;
use tokio::fs;
use tracing::info;

/// 模板引擎
pub struct TemplateEngine {
    handlebars: Handlebars<'static>,
    config: CliConfig,
}

impl TemplateEngine {
    /// 创建新的模板引擎
    pub fn new(config: &CliConfig) -> CliResult<Self> {
        let mut handlebars = Handlebars::new();
        
        // 注册帮助函数
        register_helpers(&mut handlebars)?;

        Ok(Self {
            handlebars,
            config: config.clone(),
        })
    }

    /// 渲染项目模板
    pub async fn render_project(
        &self,
        template_name: &str,
        project_config: &ProjectConfig,
    ) -> CliResult<()> {
        info!("渲染项目模板: {}", template_name);

        // 获取模板路径
        let template_path = self.get_template_path(template_name).await?;

        // 准备模板变量
        let variables = self.prepare_template_variables(project_config)?;

        // 渲染模板文件
        self.render_template_files(&template_path, &project_config.path, &variables)
            .await?;

        Ok(())
    }

    /// 获取模板路径
    async fn get_template_path(&self, template_name: &str) -> CliResult<std::path::PathBuf> {
        // 首先检查本地模板
        if let Some(local_dir) = &self.config.templates.local_dir {
            let local_path = local_dir.join(template_name);
            if local_path.exists() {
                return Ok(local_path);
            }
        }

        // 检查缓存的模板
        let cache_dir = self.config.cache_dir()?;
        let cached_path = cache_dir.join("templates").join(template_name);
        if cached_path.exists() {
            return Ok(cached_path);
        }

        // 下载模板（如果需要）
        self.download_template(template_name).await
    }

    /// 下载模板
    async fn download_template(&self, template_name: &str) -> CliResult<std::path::PathBuf> {
        info!("下载模板: {}", template_name);

        let cache_dir = self.config.cache_dir()?;
        let templates_dir = cache_dir.join("templates");
        fs::create_dir_all(&templates_dir).await?;

        // TODO: 实现从远程仓库下载模板的逻辑
        // 这里暂时创建一个基础模板
        self.create_basic_template(&templates_dir, template_name)
            .await
    }

    /// 创建基础模板
    async fn create_basic_template(
        &self,
        templates_dir: &Path,
        template_name: &str,
    ) -> CliResult<std::path::PathBuf> {
        let template_dir = templates_dir.join(template_name);
        fs::create_dir_all(&template_dir).await?;

        // 创建基础的 Cargo.toml 模板
        let cargo_toml = r#"[package]
name = "{{project_name}}"
version = "0.1.0"
edition = "2021"
description = "{{description}}"
authors = ["{{author}} <{{email}}>"]
license = "{{license}}"

[dependencies]
rustcloud = { version = "0.1.0" }
tokio = { version = "1.0", features = ["full"] }
tracing = "0.1"
tracing-subscriber = "0.3"
serde = { version = "1.0", features = ["derive"] }
anyhow = "1.0"
"#;

        fs::write(template_dir.join("Cargo.toml.hbs"), cargo_toml).await?;

        // 创建基础的 main.rs 模板
        let main_rs = r#"//! # {{project_name}}
//!
//! {{description}}

use rustcloud::prelude::*;
use tracing::{info, error};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 初始化日志
    tracing_subscriber::init();

    info!("🚀 启动 {{project_name}}");

    // 创建 RustCloud 应用
    let app = RustCloudBuilder::new("{{project_name}}")
        .with_port(8080)
        .with_registry("nacos://127.0.0.1:8848")
        .enable_metrics()
        .enable_tracing()
        .build()
        .await?;

    // 启动应用
    app.start().await?;

    info!("✅ {{project_name}} 启动完成，监听端口 8080");

    // 等待关闭信号
    tokio::signal::ctrl_c().await?;

    info!("📴 正在关闭 {{project_name}}...");

    // 优雅关闭
    app.stop().await?;

    info!("✅ {{project_name}} 已关闭");

    Ok(())
}
"#;

        fs::create_dir_all(template_dir.join("src")).await?;
        fs::write(template_dir.join("src").join("main.rs.hbs"), main_rs).await?;

        // 创建基础的 README.md 模板
        let readme = r#"# {{project_name}}

{{description}}

## 🚀 快速开始

### 安装依赖

```bash
cargo build
```

### 运行服务

```bash
cargo run
```

### 配置

创建 `config.toml` 文件：

```toml
[service]
name = "{{project_name}}"
port = 8080

[registry]
type = "nacos"
endpoints = ["127.0.0.1:8848"]
```

## 📊 监控

- 健康检查: http://localhost:8081/health
- 指标: http://localhost:9090/metrics

## 📄 许可证

{{license}}
"#;

        fs::write(template_dir.join("README.md.hbs"), readme).await?;

        Ok(template_dir)
    }

    /// 准备模板变量
    fn prepare_template_variables(
        &self,
        project_config: &ProjectConfig,
    ) -> CliResult<HashMap<String, serde_json::Value>> {
        let mut variables = HashMap::new();

        variables.insert("project_name".to_string(), json!(project_config.name));
        variables.insert("description".to_string(), json!(project_config.description));
        variables.insert("author".to_string(), json!(project_config.author));
        variables.insert("email".to_string(), json!(project_config.email));
        variables.insert("license".to_string(), json!(project_config.license));
        variables.insert("private".to_string(), json!(project_config.private));

        // 添加日期时间变量
        let now = chrono::Utc::now();
        variables.insert("year".to_string(), json!(now.format("%Y").to_string()));
        variables.insert("date".to_string(), json!(now.format("%Y-%m-%d").to_string()));
        variables.insert(
            "datetime".to_string(),
            json!(now.format("%Y-%m-%d %H:%M:%S UTC").to_string()),
        );

        Ok(variables)
    }

    /// 渲染模板文件
    async fn render_template_files(
        &self,
        template_path: &Path,
        output_path: &Path,
        variables: &HashMap<String, serde_json::Value>,
    ) -> CliResult<()> {
        use walkdir::WalkDir;
        
        for entry in WalkDir::new(template_path) {
            let entry = entry.map_err(|e| crate::error::CliError::general(format!("Walk directory error: {}", e)))?;
            let entry_path = entry.path();
            
            if entry_path.is_file() {
                let relative_path = entry_path.strip_prefix(template_path)
                    .map_err(|e| crate::error::CliError::general(format!("Strip prefix error: {}", e)))?;
                
                let file_name_str = entry_path.file_name()
                    .and_then(|n| n.to_str())
                    .unwrap_or("");
                
                let output_file_path = if file_name_str.ends_with(".hbs") {
                    // 移除 .hbs 扩展名
                    let new_name = file_name_str.trim_end_matches(".hbs");
                    let mut new_relative_path = relative_path.to_path_buf();
                    new_relative_path.set_file_name(new_name);
                    output_path.join(new_relative_path)
                } else {
                    output_path.join(relative_path)
                };
                
                // 确保输出目录存在
                if let Some(parent) = output_file_path.parent() {
                    fs::create_dir_all(parent).await?;
                }
                
                if file_name_str.ends_with(".hbs") {
                    // 渲染模板文件
                    let content = fs::read_to_string(&entry_path).await?;
                    let rendered = self.handlebars.render_template(&content, variables)?;
                    fs::write(output_file_path, rendered).await?;
                } else {
                    // 直接复制非模板文件
                    fs::copy(&entry_path, output_file_path).await?;
                }
            }
        }

        Ok(())
    }
}

/// 注册 Handlebars 帮助函数
fn register_helpers(handlebars: &mut Handlebars) -> CliResult<()> {
    // 注册大写转换帮助函数
    handlebars.register_helper(
        "uppercase",
        Box::new(|h: &handlebars::Helper, _: &handlebars::Handlebars, _: &handlebars::Context, _: &mut handlebars::RenderContext, out: &mut dyn handlebars::Output| {
            let param = h.param(0).and_then(|v| v.value().as_str()).unwrap_or("");
            out.write(&param.to_uppercase())?;
            Ok(())
        }),
    );

    // 注册小写转换帮助函数
    handlebars.register_helper(
        "lowercase",
        Box::new(|h: &handlebars::Helper, _: &handlebars::Handlebars, _: &handlebars::Context, _: &mut handlebars::RenderContext, out: &mut dyn handlebars::Output| {
            let param = h.param(0).and_then(|v| v.value().as_str()).unwrap_or("");
            out.write(&param.to_lowercase())?;
            Ok(())
        }),
    );

    // 注册蛇形命名帮助函数
    handlebars.register_helper(
        "snake_case",
        Box::new(|h: &handlebars::Helper, _: &handlebars::Handlebars, _: &handlebars::Context, _: &mut handlebars::RenderContext, out: &mut dyn handlebars::Output| {
            let param = h.param(0).and_then(|v| v.value().as_str()).unwrap_or("");
            let snake_case = param
                .replace("-", "_")
                .replace(" ", "_")
                .to_lowercase();
            out.write(&snake_case)?;
            Ok(())
        }),
    );

    // 注册驼峰命名帮助函数
    handlebars.register_helper(
        "camel_case",
        Box::new(|h: &handlebars::Helper, _: &handlebars::Handlebars, _: &handlebars::Context, _: &mut handlebars::RenderContext, out: &mut dyn handlebars::Output| {
            let param = h.param(0).and_then(|v| v.value().as_str()).unwrap_or("");
            let camel_case = param
                .split(&['-', '_', ' '][..])
                .enumerate()
                .map(|(i, s)| {
                    if i == 0 {
                        s.to_lowercase()
                    } else {
                        capitalize_first_letter(s)
                    }
                })
                .collect::<String>();
            out.write(&camel_case)?;
            Ok(())
        }),
    );

    Ok(())
}

/// 首字母大写
fn capitalize_first_letter(s: &str) -> String {
    s.chars()
        .take(1)
        .flat_map(|f| f.to_uppercase())
        .chain(s.chars().skip(1).flat_map(|c| c.to_lowercase()))
        .collect()
}